<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen 1.9.1"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>libconfini: Get involved</title>
<link href="tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="dynsections.js"></script>
<link href="search/search.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="search/searchdata.js"></script>
<script type="text/javascript" src="search/search.js"></script>
<link href="doxygen.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<table cellspacing="0" cellpadding="0">
 <tbody>
 <tr style="height: 56px;">
  <td id="projectalign" style="padding-left: 0.5em;">
   <div id="projectname">libconfini
   </div>
   <div id="projectbrief">Yet another INI parser</div>
  </td>
 </tr>
 </tbody>
</table>
</div>
<!-- end header part -->
<!-- Generated by Doxygen 1.9.1 -->
<script type="text/javascript">
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
var searchBox = new SearchBox("searchBox", "search",false,'Search','.html');
/* @license-end */
</script>
<script type="text/javascript" src="menudata.js"></script>
<script type="text/javascript" src="menu.js"></script>
<script type="text/javascript">
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
$(function() {
  initMenu('',true,false,'search.php','Search');
  $(document).ready(function() { init_search(); });
});
/* @license-end */</script>
<div id="main-nav"></div>
<!-- window showing the filter options -->
<div id="MSearchSelectWindow"
     onmouseover="return searchBox.OnSearchSelectShow()"
     onmouseout="return searchBox.OnSearchSelectHide()"
     onkeydown="return searchBox.OnSearchSelectKey(event)">
</div>

<!-- iframe showing the search results (closed by default) -->
<div id="MSearchResultsWindow">
<iframe src="javascript:void(0)" frameborder="0" 
        name="MSearchResults" id="MSearchResults">
</iframe>
</div>

</div><!-- top -->
<div class="PageDoc"><div class="header">
  <div class="headertitle">
<div class="title">Get involved </div>  </div>
</div><!--header-->
<div class="contents">
<div class="textblock"><p>Developing <b>libconfini</b></p>
<p><a class="anchor" id="md_dev_docs_develop"></a></p>
<p>If you want to participate in the development of <b>libconfini</b>, the <code>dev</code> subdirectory is where all the source files that matter are located (of both the library and the documentation).</p>
<p>There is always room for improving the documentation, especially concerning style, grammar and clarity.</p>
<p>If you want to propose fresh code, please make sure to apply your changes to <code>dev/marked-sources/confini-marked.c</code> and <code>dev/marked-sources/confini-marked.h</code> instead of <code><a class="el" href="confini_8c.html" title="libconfini functions">src/confini.c</a></code> and <code><a class="el" href="confini_8h.html" title="libconfini header">src/confini.h</a></code> (the latter are automatically generated). You can afterwards launch</p>
<div class="fragment"><div class="line">./configure --enable-author-mode</div>
<div class="line">make all-official-sources</div>
</div><!-- fragment --><p>to update the <code>src</code> subdirectory.</p>
<p>Currently only two I/O standards are supported: the C Standard and the POSIX Standard. If you believe that <b>libconfini</b> should also support an I/O API provided by a non-standard header (such as <code>fsio.h</code>, <code>mem-ffs.h</code>, <code>efs.h</code> or <code>ff.h</code>), please do not hesitate to <a href="https://github.com/madmurphy/libconfini/issues">propose it</a>.</p>
<h1>Strangeness warning </h1>
<p>If you have had a look at the source code of <b>libconfini</b> already, you have probably noticed something odd about it: the abundance of what seems to be magic numbers.</p>
<p>The reason behind them has to do with the fact that the library needs to be able to support thousands of INI dialects without slowing down. If you want to understand how this works, please follow me.</p>
<p>The <code><a class="el" href="structIniFormat.html" title="24-bit bitfield representing the format of an INI file (INI dialect)">IniFormat</a></code> bitfield occupies 24 bits. After collapsing the seven bits of <code><a class="el" href="structIniFormat.html#a6d9981301f5a16d73e2c38cb80f7f962">IniFormat::delimiter_symbol</a></code> into one single bit (complexity-wise there are only two meaningful states for this field: <code>INI_ANY_SPACE</code> and any normal character) it becomes 18 bits wide. This corresponds to 2¹⁸ (262144) possible INI formats. Three fields however make sense only if some other fields are set to a particular state (<code><a class="el" href="structIniFormat.html#ab5937aaf72b0ce5b62aece8d23ad7b82">IniFormat::disabled_can_be_implicit</a></code> and <code><a class="el" href="structIniFormat.html#a6ad00ea76bbe5ed109f4192f89859656">IniFormat::disabled_after_space</a></code> are no-op when the format does not support disabled entries, and <code><a class="el" href="structIniFormat.html#ad224b6997bbb99d4715fba8a8bea4cd7">IniFormat::preserve_empty_quotes</a></code> is no-op when the format does not support quotes); this lowers the number of available possible formats down to 110592. It goes without saying that <b>libconfini</b> must support all of them.</p>
<p>Many of the consequences that each format carries manifest during loops that scroll through each character of the parsed INI file. Inserting conditions inside loops creates slow code, and if these conditions are not going to change during the loop, unacceptable code &ndash; for instance, it does not make much sense to check for every character whether a format supports quotes or not, this is something that will remain constant during the entire parsing. The normal solution would be that of keeping the constant conditions outside the loops and creating slightly different loops for each case, but this is unthinkable with 110592 possibilities. There is however also a third way: bit masks. Bit masks allow to collapse several conditions into one single operation and keep the complexity constant.</p>
<p>Let us make a concrete example.</p>
<p>A format that supports quotes needs to check if a backslash precedes the quotes or not. This check would be needed even if our parser supported only one single format, it is simply part of the quotes feature.</p>
<p>Let us imagine that we create a boolean named <code>b_backslash_precedes</code> for that. For every character the loop will have to check something similar to &lsquo;chr == &rsquo;"' &amp;&amp; !b_backslash_precedes`.</p>
<p>With multiple formats though, the check would have to become <code>chr == '"' &amp;&amp; !b_backslash_precedes &amp;&amp; !b_format_no_quotes</code> &ndash; with one more check to do, and the ugly reality that <code>b_format_no_quotes</code> would remain constant for the entire loop.</p>
<p>However, if <code>b_backslash_precedes</code> were the flag <code>1</code> of a bit mask and we used <code>chr == '"' &amp;&amp; !(bitmask &amp; 1)</code> for the first check, adding also the second
check would simply transform the condition into <code>chr == '"' &amp;&amp; !(bitmask &amp; 3)</code> &ndash; with <code>b_format_no_quotes</code> corresponding to the bit <code>2</code> of the bit mask. No operations would be added, only the numbers would change. The fact that we are checking a constant on every character has become irrelevant; doing <code>bitmask &amp; 3</code> will not be slower than doing <code>bitmask &amp; 1</code>.</p>
<p>This example illustrates how bit masks can collapse several conditions into single operations and ease the repercussions on the final performance. Unfortunately the conditions <b>libconfini</b> has to check are usually never just two, but dozens each time. And while bit masks do keep the number of branches constant, they definitely look esoteric.</p>
<p>The usual way to avoid esoteric code is that of using <code>enum</code> labels for bitflags. With <b>libconfini</b> however this would not help much: bitflags are used so often that it would just fill the entire source code of <code>enum</code>s. The esoterism would just change form.</p>
<p>I am sorry if the code scares you, but there are no other ways, I am afraid.¹ If you want to understand how the library works you will have to get used to deal with magic numbers. Once you have learned how to read them, though, they will look a bit less magic; or at least not more magic than any other ordinary ollection of bit flags.</p>
<h1>Notes </h1>
<ol type="1">
<li>Lately it has been explored the possibility of using the m4 preprocessor for templating the functions that make heavy use of bit masks. This solution seems to create an acceptable compromise; however it has been explored only very recently, and rewriting in another language code that already works only for the sake of having human-friendly labels is not a worthy goal. The finding will make it possible nonetheless, from now on, to create such m4 templates “on demand” every time a bug in one of the existing functions is discovered (for facilitating the analysis), or when a new feature is introduced. </li>
</ol>
</div></div><!-- contents -->
</div><!-- PageDoc -->
<!-- start footer part -->
<hr class="footer"/><address class="footer"><small>
Generated by&#160;<a href="https://www.doxygen.org/index.html"><img class="footer" src="doxygen.svg" width="104" height="31" alt="doxygen"/></a> 1.9.1
</small></address>
</body>
</html>
